// 服务器：使客户端和服务器能够建立连接，进行网络通信的文件
#pragma once

#include "Socket.hpp"
#include "servercalc.hpp"

#include <iostream>
#include <unistd.h>
#include <signal.h>
#include <functional>

using func_t = std::function<std::string(std::string &c_req_package)>;

class TcpServer
{
public:
    TcpServer(uint16_t port, func_t callback)
        : _port(port), _callback(callback)
    {
    }
    ~TcpServer() {}

public:
    bool InitServer()
    {
        _listen_sockfd.Socket();
        _listen_sockfd.Bind(_port);
        _listen_sockfd.Listen();
    }
    void StartServer()
    {
        signal(SIGCHLD, SIG_IGN);
        signal(SIGPIPE, SIG_IGN);
        while (true)
        {
            // 建立连接
            std::string clientip;
            uint16_t clientport;
            int sockfd = _listen_sockfd.Accept(&clientip, &clientport);
            if (sockfd < 0)
                continue;

            // 提供服务---多进程版本
            pid_t id = fork();
            if (id == 0)
            {
                _listen_sockfd.Close();
                std::string inbuffer_stream;
                // 读取Client发来的报文，解析报文，计算数据，构建返回报文--servercalc.hpp
                while (true)
                {
                    // read
                    char buffer[128];
                    ssize_t n = read(sockfd, buffer, sizeof(buffer));
                    if (n > 0)
                    {
                        buffer[n] = 0;
                        // inbuffer_stream中存放的可能是多个报文，或者有半截的报文。
                        // 所以一次_callback无法完成多个报文的解析，所以用inbuffer_stream进行暂存
                        inbuffer_stream += buffer;
                        std::cout << "inbuffer_stream:" << inbuffer_stream << std::endl;
                        while (true) //处理一次发来多个报文的情况， 一次处理多个报文
                        {
                            std::string info = _callback(inbuffer_stream);
                            //std::cout << "info" << info << std::endl;
                            // write
                            if (info == "none")
                                break; // 这个是Client报文格式错误，可以重新读取
                            write(sockfd, info.c_str(), info.size());
                        }
                    }
                    else if (n == 0)
                        break; // 这两个是断开连接，或其他情况导致不可通信才结束进程
                    else
                        break;
                }
                exit(0);
            }
            close(sockfd);
        }
    }

private:
    uint16_t _port;
    Sock _listen_sockfd;
    func_t _callback;
};


//server和client建立连接后，如果client不发消息，也不关闭，那么就会一直占用系统资源，可以设置10秒不发数据就断开连接等措施